package server.network;

import java.io.*;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.HashMap;

import common.message.*;
import common.message.clientSend.*;
import common.message.serverSend.*;
import common.types.*;
import server.config.Public;
import server.doc.xml.XMLChatHistory;
import server.doc.xml.XMLUserProfile;
import server.models.*;
import server.views.ServerMain;

/**
 * 
 * @author solomon
 *
 */

public class ReceiveThread implements Runnable {
	private int userID;

	private ObjectInputStream ois;

	private boolean stop = false;

	private Message dataPacket = null;

	private ServerMain f;
	private XMLUserProfile xmlProfile = XMLUserProfile.getInstance();

	public ReceiveThread(int uid, ObjectInputStream ois, ServerMain f) {
		this.userID = uid;
		this.ois = ois;
		this.f = f;
	}

	public void run() {
		while (!stop) {		
			try {
				dataPacket = (Message) ois.readObject();

				if (dataPacket instanceof ChatWithFriendMsg) {
					// re-direct to the receiver and write into xml
					ChatWithFriendMsg chatMsgPacket = (ChatWithFriendMsg) dataPacket;
					chatMsgPacket.setTime();

					int from = chatMsgPacket.getFromUserID();
					int to = chatMsgPacket.getToUserID();
					ObjectOutputStream oos = Public.clientOStream.get(new Integer(to));
					oos.writeObject(chatMsgPacket);
					oos.flush();
					XMLChatHistory chatHistory = new XMLChatHistory(from);
					chatHistory.addItem(from, to, chatMsgPacket.getMessage());
					chatHistory = new XMLChatHistory(to);
					chatHistory.addItem(from, to, chatMsgPacket.getMessage());
				} else if (dataPacket instanceof AddFriendMsg) {
					AddFriendMsg addFriendPacket = (AddFriendMsg) dataPacket;
					int userID = addFriendPacket.getFromUserID();
					int friendUID = addFriendPacket.getFriendUID();
					if (userID != friendUID && !xmlProfile.friendExists(userID, friendUID)) {
						if (!xmlProfile.userExists(friendUID)) {
							ObjectOutputStream oos = Public.clientOStream.get(new Integer(userID));
							oos.writeObject(new ServerDenyMsg(userID, "user doesn't exist", addFriendPacket));
							oos.flush();
						} else {
							xmlProfile.addFriend(userID, friendUID);
							xmlProfile.addFriend(friendUID, userID);
							ObjectOutputStream oos = Public.clientOStream.get(new Integer(userID));
							sendNewFriendList(oos, userID);
							if (Public.status.getStatus(friendUID) == StatusType.online) {
								oos = Public.clientOStream.get(new Integer(friendUID));
								sendNewFriendList(oos, friendUID);
							}
						}
					}
				} else if (dataPacket instanceof GetChatHistoryMsg) {
					GetChatHistoryMsg getHistoryPacket = (GetChatHistoryMsg) dataPacket;
					int uid = getHistoryPacket.getUserID();
					int fuid = getHistoryPacket.getFriendUID();
					ChatHistoryMsg historyPacket = new ChatHistoryMsg(uid, fuid,
							new XMLChatHistory(getHistoryPacket.getUserID()).getHistory(fuid));
					ObjectOutputStream oos = Public.clientOStream.get(new Integer(uid));
					oos.writeObject(historyPacket);
					oos.flush();
				} else if (dataPacket instanceof RemoveFriendMsg) {
					RemoveFriendMsg removeFriendPacket = (RemoveFriendMsg) dataPacket;
					int userID = removeFriendPacket.getFromUserID();
					int friendUID = removeFriendPacket.getFriendUID();
					try {
						xmlProfile.deleteFriend(userID, friendUID);
						xmlProfile.deleteFriend(friendUID, userID);
						ObjectOutputStream oos = Public.clientOStream.get(new Integer(userID));
						sendNewFriendList(oos, userID);
						if (Public.status.getStatus(friendUID) == StatusType.online) {
							oos = Public.clientOStream.get(new Integer(friendUID));
							sendNewFriendList(oos, friendUID);
						}	
					} catch (Error e) {
						ObjectOutputStream oos = Public.clientOStream.get(new Integer(userID));
						oos.writeObject(new ServerDenyMsg(userID, "no such friend", removeFriendPacket));
						oos.flush();
					}
				} else if (dataPacket instanceof GetUserProfileMsg) {
					// send some profile back to the client
					GetUserProfileMsg getProfilePacket = (GetUserProfileMsg) dataPacket;
					int quid = getProfilePacket.getQueryUserID();
					UserProfile profile = xmlProfile.getUser(quid);
					UserProfileMsg userProfilePacket = new UserProfileMsg(userID, quid, profile.getName(), profile.getGender(), profile.getAge());
					ObjectOutputStream oos = Public.clientOStream.get(new Integer(userID));
					oos.writeObject(userProfilePacket);
					oos.flush();
				} /*else if (dataPacket instanceof GetUserStatusMsg) {
					// send some status back to the client
					GetUserStatusMsg getStatusPacket = (GetUserStatusMsg) dataPacket;

				}*/ else if (dataPacket instanceof UpdateProfileMsg) {
					// update profile and send a message back when successful
					UpdateProfileMsg updateProfilePacket = (UpdateProfileMsg) dataPacket;
					UserProfile oldProfile = xmlProfile.getUser(userID);
					UserProfile newProfile = new UserProfile(userID,
							oldProfile.getPassword(), updateProfilePacket.getName(),
							updateProfilePacket.getGender(), updateProfilePacket.getAge(), oldProfile.getFriends());
					xmlProfile.updateEntry(newProfile);
					ServerConfirmMsg confirmPacket = new ServerConfirmMsg(userID, "new profile saved", updateProfilePacket);
					ObjectOutputStream oos = Public.clientOStream.get(new Integer(userID));
					oos.writeObject(confirmPacket);
					oos.flush();
					ArrayList<ArrayList<String>> profileList = new ArrayList<ArrayList<String>>();
					for (UserProfile profile : xmlProfile.getUsers()) {
						ArrayList<String> strProfile = new ArrayList<String>();
						strProfile.add(Integer.toString(profile.getUserID()));
						strProfile.add(profile.getName());
						strProfile.add(profile.getGender().toString());
						strProfile.add(Integer.toString(profile.getAge()));
						profileList.add(strProfile);
					}					
					f.getUserMngPanel().getCenterPanel().getDataModel().setData(profileList);
				} else if (dataPacket instanceof UpdatePwdMsg) {
					// update password and send a message back when successful
					UpdatePwdMsg updatePwdPacket = (UpdatePwdMsg) dataPacket;
					UserProfile profile = xmlProfile.getUser(userID);
					Message msg;
					if (updatePwdPacket.getOldPassword() != profile.getPassword())
						msg = new ServerDenyMsg(userID, "wrong password!", updatePwdPacket);
					else {
						profile.setPassword(updatePwdPacket.getNewPassword());
						xmlProfile.updateEntry(profile);
						msg = new ServerConfirmMsg(userID, "new password saved", updatePwdPacket);
					}
					ObjectOutputStream oos = Public.clientOStream.get(new Integer(userID));
					oos.writeObject(msg);
					oos.flush();
				} else if (dataPacket instanceof UserLoginMsg) {
					throw new Error("User already logged in");
				} else if (dataPacket instanceof UserLogoutMsg) {
					// no confirm. send status to other clients.
					sendOfflinePacket();
					/*					Public.status.setStatus(userID, StatusType.offline);
					for (Integer uid : Public.status.getOnlineUsers()) {
						UserStatusMsg statusPacket = new UserStatusMsg(uid.intValue(), userID, StatusType.offline);
						ObjectOutputStream oos = Public.clientOStream.get(uid);
						oos.writeObject(statusPacket);
					}*/
				} else
					throw new Error("Undefined message");


			} catch (SocketException e) {
				// 向所有用户发下线包
				sendOfflinePacket();
				return;
			} catch (IOException e) {
				return;
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
				return;
			}
		}
	}

	public void sendNewFriendList(ObjectOutputStream oos, int uid) {
		UserProfile profile = xmlProfile.getUser(uid);
		ArrayList<Integer> friends = profile.getFriends();
		HashMap<Integer, String> friendsName = new HashMap<Integer, String>();
		HashMap<Integer, StatusType> friendsStatus = new HashMap<Integer, StatusType>();
		for (Integer fuid : friends) {
			friendsName.put(fuid, xmlProfile.getUser(fuid).getName());
			friendsStatus.put(fuid, Public.status.getStatus(fuid));
		}
		try {
			oos.writeObject(new FriendListMsg(uid, friends, friendsName, friendsStatus));
			oos.flush();
		} catch (IOException e) {
			return;
		}
	}

	public void sendOfflinePacket() {
		Public.status.setStatus(userID, StatusType.offline);
		Public.clientIStream.remove(userID);
		Public.clientOStream.remove(userID);
		Public.clientSocket.remove(userID);
		Public.clientThreads.remove(userID);
		for (Integer uid : Public.status.getOnlineUsers()) {
			ObjectOutputStream oos = Public.clientOStream.get(uid);
			try {
				oos.writeObject(new UserStatusMsg(uid.intValue(), userID, StatusType.offline));
				oos.flush();
			} catch (IOException e) {
				return;
			}
		}
		// 刷新在线用户的显示
		ArrayList<ArrayList<String>> profileList = new ArrayList<ArrayList<String>>();
		for (Integer user : Public.status.getOnlineUsers()) {
			ArrayList<String> strProfile = new ArrayList<String>();
			strProfile.add(user.toString());
			UserProfile profile = xmlProfile.getUser(user.intValue());
			strProfile.add(profile.getName());
			strProfile.add(profile.getGender().toString());
			strProfile.add(Public.dateFormat.format(Public.status.getOnlineTime(user.intValue())));
			profileList.add(strProfile);
		}
		f.getServerMngPanel().getTablePanel().getDataModel().setData(profileList);
	}

	/*	public void sendUpdateTreePacket() {
		Set set = (Set) Public.mySocketInfo.keySet();
		Iterator iter = set.iterator();
		String[] QQ_id = new String[set.size()];
		int i = 0;
		//System.out.println(set.size());
		while (iter.hasNext()) {
			QQ_id[i] = (String) iter.next();
			//System.out.println(QQ_id[i]);
			if (!QQ_id[i].equals(id)) {
				ArrayList arry = (ArrayList) Public.mySocketInfo.get(QQ_id[i]);
				ObjectOutputStream tempOos = (ObjectOutputStream) arry.get(2);// 取出list里的输出流
				Message updateTreePacket = new Message(
						Message.update_tree_type, id, "", null);
				if (updateTreePacket != null) {
					try {
						// 发出下线包
						tempOos.writeObject(updateTreePacket);
						tempOos.flush();
					} catch (IOException e) {
						return;
					}
				}
			}
			i++;
		}
//		Public.mySocketInfo.remove(id);
//		// 修改数据库的用户表的用户在线字段改成0
//		userDao.updateOnLine(0, id);
		// 刷新在线用户的显示
		h.put("9", "");
		Vector vector = userDao.selectUser(h);
		h.clear();
		f.getServerMngPanel().getTablePanel().getDataModel().setData(vector);
	}*/

}
